package com.weilele.leisure.time.ui.player


import android.Manifest
import android.os.Environment
import android.os.FileUtils
import android.provider.MediaStore
import android.view.View
import androidx.annotation.WorkerThread
import androidx.core.app.ActivityCompat
import androidx.core.database.getStringOrNull
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import cn.leancloud.utils.FileUtil
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.offline.Download
import com.google.android.exoplayer2.util.MimeTypes
import com.weilele.leisure.time.R
import com.weilele.mvvm.adapter.ignoreError
import com.weilele.mvvm.app
import com.weilele.mvvm.base.livedata.StatusData
import com.weilele.mvvm.base.livedata.createStatusLiveData
import com.weilele.mvvm.base.livedata.data
import com.weilele.mvvm.base.livedata.success
import com.weilele.mvvm.utils.activity.getActivity
import com.weilele.mvvm.utils.activity.getResString
import com.weilele.mvvm.utils.activity.toast
import com.weilele.mvvm.utils.coroutine.launchOnThread
import com.weilele.mvvm.utils.file.SaveFileType
import com.weilele.mvvm.utils.file.insetFileToContentResolver
import com.weilele.mvvm.utils.file.parseVideoInfo
import com.weilele.mvvm.utils.formatLength
import com.weilele.mvvm.utils.logI
import com.weilele.mvvm.utils.longTimeToStr
import com.weilele.mvvm.utils.permission.checkPermission
import com.yizisu.playerlibrary.service.download.PlayerDownload
import com.yizisu.playerlibrary.service.download.PlayerTransformer
import kotlinx.coroutines.GlobalScope
import java.io.File
import java.lang.Exception

/**
 * 视频格式转换工具类
 */
object TransformingMediaHelper {

    private val taskDataMap = mutableMapOf<String, MutableLiveData<StatusData<TransformingInfo>>>()

    data class TransformingInfo(
        var success: Boolean,
        var message: String,
    )

    /**
     * 检查是否任务已经存在
     */
    fun checkTaskData(download: Download): LiveData<StatusData<TransformingInfo>>? {
        return taskDataMap[download.request.id]
    }

    /**
     * 开始视频转换
     */
    fun startTransformer(
        view: View,
        download: Download,
        fileName: String,
        mimeType: PlayerTransformer.OutputType = PlayerTransformer.OutputType.VideoMp4
    ): Boolean {
        val activity = view.getActivity() ?: return false
        if (activity.checkPermission(
                listOf(
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
                )
            ).isNotEmpty()
        ) {
            ActivityCompat.requestPermissions(
                activity,
                arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),
                200
            )
            "没有写入存储权限".toast()
            return false
        }
        val id = download.request.id
        val checkData = checkTaskData(download)
        if (checkData != null) {//任务已经存在
            return false
        }
        val path = app.getExternalFilesDir(Environment.DIRECTORY_MOVIES)?.path ?: return false
        taskDataMap[id] = createStatusLiveData()
        val filePath = "${path}/${fileName}.mp4"
        val mediaItem = download.request.toMediaItem()
        PlayerTransformer(mediaItem, filePath, true, mimeType).apply {
            setTransformerListener { progress, success, error ->
                if (success) {
                    GlobalScope.launchOnThread {
                        saveVideoToPublic(id, filePath, fileName, mimeType.mimeType)
                    }
                } else {
                    updateTaskData(id, false, "${progress}%")
                }
                if (error != null) {
                    taskDataMap.remove(id)
                }
            }
            ignoreError { start() }
        }
        return true
    }

    private fun updateTaskData(id: String, success: Boolean, message: String) {
        val data = taskDataMap[id]
        if (data == null) {
            taskDataMap[id] = createStatusLiveData<TransformingInfo>().apply {
                success(TransformingInfo(success, message))
            }
        } else {
            val transformingInfo = data.data
            if (transformingInfo == null) {
                data.success(TransformingInfo(success, message))
            } else {
                transformingInfo.success = false
                transformingInfo.message = message
                data.success(transformingInfo)
            }
        }
    }

    /**
     * 将文件写入到公共文件夹
     */
    @WorkerThread
    private fun saveVideoToPublic(
        id: String,
        filePath: String,
        name: String?,
        mimeType: String
    ) {
        updateTaskData(id, false, "合并中")
        var fileName = name
        if (fileName.isNullOrBlank()) {
            fileName = System.currentTimeMillis().toString()
        }
        val file = File(filePath)
        if (!file.exists()) {
            logI { "文件（$filePath）不存在" }
            updateTaskData(id, false, "完成")
            return
        }
        val fileLength = file.length()
        logI {
            "开始写入公共文件夹--》${
                longTimeToStr(
                    System.currentTimeMillis(),
                    "yyyy-MM-dd HH:mm:ss.SSS"
                )
            }  大小：${fileLength.formatLength()}"
        }
        val videoInfo = parseVideoInfo(filePath)
        logI {
            "解析视频信息：${videoInfo}  ${
                longTimeToStr(
                    System.currentTimeMillis(),
                    "yyyy-MM-dd HH:mm:ss.SSS"
                )
            }"
        }
        val uri = insetFileToContentResolver(
            SaveFileType.Video,
            mimeType,
            "$fileName.mp4",
            "${getResString(R.string.app_name)}"
        ) {
            it.put(MediaStore.Video.Media.DURATION, videoInfo.first)
            it.put(MediaStore.Video.Media.WIDTH, videoInfo.second)
            it.put(MediaStore.Video.Media.HEIGHT, videoInfo.third)
        }
        if (uri == null) {
            logI { "uri is null" }
            updateTaskData(id, false, "完成")
            return
        }
        app.contentResolver.openOutputStream(uri)?.use { output ->
            file.inputStream().use { input ->
                var bytesCopied: Long = 0
                val buffer = ByteArray(DEFAULT_BUFFER_SIZE)
                var bytes = input.read(buffer)
                while (bytes >= 0) {
                    output.write(buffer, 0, bytes)
                    bytesCopied += bytes
                    bytes = input.read(buffer)
                    updateTaskData(id, false, "合并${bytesCopied * 100 / fileLength}")
                }
            }
        }
        logI {
            "写入公共文件夹完成--》${
                longTimeToStr(
                    System.currentTimeMillis(),
                    "yyyy-MM-dd HH:mm:ss.SSS"
                )
            }"
        }
        //删除下载文件
        PlayerDownload.removeDownload(id)
        updateTaskData(id, true, "完成")
        taskDataMap.remove(id)
    }
}